package com.duapk.index.work;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.duapk.index.conf.ConfigFactory;
import com.duapk.index.constant.Constant;
import com.duapk.index.util.StringTools;

/**
 * 索引创建代理类
 * 
 * @Package: com.duapk.index.work
 * @ClassName: IndexProxy
 * @author: jiangzheng
 * @date: Apr 5, 2011 6:10:16 PM
 * 
 */
public class IndexProxy {

	private static Logger logger = LoggerFactory.getLogger(IndexProxy.class);

	public static void index() {
		if (logger.isDebugEnabled()) {
			logger.debug("start to create index....");
		}
		List<String> categorys = ConfigFactory
				.getList("Categorys.category[@name]");
		int workNum = 0;
		List<Integer> finishedJobs = new ArrayList<Integer>();
		for (int i = 0; i < categorys.size(); i++) {
			String category = categorys.get(i);
			List<String> sourcePaths = ConfigFactory
					.getList("Categorys.category(" + i + ").path");
			if (sourcePaths == null || sourcePaths.size() == 0) {
				continue;
			}

			List<File> csvSourceFiles = new ArrayList<File>();
			for (int j = 0; j < sourcePaths.size(); j++) {
				File sourceFile = new File(Constant.CSV_SOURCE + File.separator
						+ sourcePaths.get(j));
				if (sourceFile.isDirectory()) {
					csvSourceFiles
							.addAll(Arrays.asList(sourceFile.listFiles()));
				} else if (sourceFile.isFile()) {
					csvSourceFiles.add(sourceFile);
				}
			}
			if (csvSourceFiles.size() > 0) {
				new Thread(
						new IndexWork(csvSourceFiles, category, finishedJobs))
						.start();
				workNum++;
			}
		}

		if (workNum > 0) {
			long ts = System.currentTimeMillis();
			synchronized (finishedJobs) {
				while (true) {
					try {
						finishedJobs.wait(500);
					} catch (InterruptedException e) {
						// 不处理
					}
					// 所有索引线程创建完毕
					if (finishedJobs.size() >= workNum) {
						break;
					}
					// 索引创建时间超过一小时，则强行退出
					if ((System.currentTimeMillis() - ts) / 1000 >= 3600) {
						break;
					}
				}
			}

			// 索引移至搜索子系统时需要创建的时间目录
			long tsDir = System.currentTimeMillis();
			// 创建混合索引
			createApkIndex(Constant.INDEX_PATH + File.separator + "apk");

			moveIndexToSearch(Constant.INDEX_PATH, tsDir);
			notifySearch(tsDir);
		}
	}

	/**
	 * 通知搜索子系统更新索引
	 * 
	 * @Title: notifySearch
	 * @author: jiangzheng
	 * @date: Apr 4, 2011 7:13:11 PM
	 */
	private static void notifySearch(long ts) {
		String url = ConfigFactory.getString("Notify.url");
		HttpURLConnection conn = null;
		try {
			conn = (HttpURLConnection) new URL(url).openConnection();
			// 使用POST方式下发
			conn.setRequestMethod("POST");
			conn.setDoOutput(true);
			PrintWriter out = new PrintWriter(conn.getOutputStream());
			out.write("ts=" + ts);
			out.flush();
			out.close();
			// 检查状态码
			int status = conn.getResponseCode();
			if (status != HttpURLConnection.HTTP_OK) {
				logger.error(

				"notify search error. url is {}, ts is {}, status is {}",
						new Object[] { url, ts, status });
			}
		} catch (IOException e) {
			logger.error("notify search error. search url is " + url
					+ ", ts is " + ts, e);
		} finally {
			try {
				if (conn != null) {
					conn.disconnect();
				}
			} catch (Exception e) {
				logger.error("Disconnect Connection error.", e);
			}
		}
	}

	/**
	 * 将索引移至搜索目录
	 * 
	 * @Title: moveIndexToSearch
	 * @author: jiangzheng
	 * @date: Apr 4, 2011 7:11:10 PM
	 * @param apkIndexPath
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static void moveIndexToSearch(String indexPath, long tsDir) {

		try {
			File indexDir = new File(indexPath);
			File[] categoryDirs = indexDir.listFiles();
			for (File categoryDir : categoryDirs) {
				Process process = Runtime.getRuntime().exec(
						StringTools.getAbsolutePath("copy.sh")
								+ " "
								+ categoryDir.getAbsolutePath()
								+ " "
								+ ConfigFactory
										.getString("Path.searchIndexDir")
								+ File.separator + categoryDir.getName() + " "
								+ tsDir);
				new Thread(new StreamWork(process.getInputStream())).start();
				new Thread(new StreamWork(process.getErrorStream())).start();
				process.getOutputStream().close();
				process.waitFor();
			}

		} catch (IOException e) {
			logger.error("invoke shell error.", e);
		} catch (InterruptedException e) {
			logger.error("invoke shell error.", e);
		}

	}

	/**
	 * 创建APK应用索引
	 * 
	 * @Title: createApkIndex
	 * @author: jiangzheng
	 * @date: Apr 4, 2011 6:54:22 PM
	 * @param writer
	 */
	private static void createApkIndex(String apkIndexPath) {
		IndexWriter writer = null;
		try {
			File indexPath = new File(Constant.INDEX_PATH);
			Directory directory = FSDirectory.open(new File(apkIndexPath));
			IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_32,
					null);
			config.setOpenMode(OpenMode.CREATE);
			writer = new IndexWriter(directory, config);
			File[] categoryIndexDirs = indexPath.listFiles(new FileFilter() {
				public boolean accept(File pathname) {
					return !pathname.getName().equals("apk");
				}
			});
			Directory[] mergeDirs = new Directory[categoryIndexDirs.length];
			for (int i = 0; i < mergeDirs.length; i++) {
				mergeDirs[i] = FSDirectory.open(categoryIndexDirs[i]);
			}
			writer.addIndexes(mergeDirs);
			writer.commit();
			writer.optimize();
		} catch (IOException e) {
			logger.error("create apk index error.", e);
		} finally {
			if (writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					logger.error("close IndexWriter error.", e);
				}
			}
		}
		if (logger.isDebugEnabled()) {
			logger.debug("end to create index....");
		}
	}
}
